﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Portfolio.BL.Interfaces;
using Portfolio.Entities;
using Portfolio.Repository.Common;
using Portfolio.Repository.Categories;
using Portfolio.Repository.Articles;
using Portfolio.Repository.Interfaces;
using Portfolio.BL.Enumerations;
using Portfolio.BL.Dictionary;
using Portfolio.BL.Common;

namespace Portfolio.BL.Categories
{
    
    /// <summary>
    /// Klasa biznesowa Kategoria
    /// </summary>
    public class CategoriesBL : InformationUser 
    {
        private Portfolio3Entities _context;
        private CategoriesRepository _categoriesRepository;
        private ArticleCategoryT _articleCategory = new ArticleCategoryT();
        private List<ArtcileCategoriesGridV> _listGridArticleCategories = new List<ArtcileCategoriesGridV>();
        
        
        public CategoriesBL() : base()
        {
            _context = new Portfolio3Entities();
            _categoriesRepository = new CategoriesRepository(_context);
        }
        /// <summary>
        /// Właściwość zwraca kategorie artykułu
        /// </summary>
        public ArticleCategoryT ArticleCategory
        {
            get
            {
                return _articleCategory;
            }            
        }

        /// <summary>
        /// Właściwość zwraca liste kategorii artykułów dla girda
        /// </summary>
        public List<ArtcileCategoriesGridV> ListGridArticleCategories
        {
            get
            {
                return _listGridArticleCategories;
            }
        }
        
        /// <summary>
        /// Metoda użytkownika
        /// Przypisuje wszystkie dane z konkretnej kategorii
        /// </summary>
        /// <param name="idArticleCategory">id kategori</param>
        public void ReturnArticleCategoryById(int pArticleCategoryID)
        {
            try
            {                
                if (pArticleCategoryID != 0)
                {
                    _articleCategory = _categoriesRepository.GetCategoryByIdCategory(pArticleCategoryID);
                }                              
                
            }
            catch (Exception ex)
            {
                InformationException = "Błąd podczas ładowania kategorii! " + ex.Message;                
            }
        }

        /// <summary>
        /// Metoda użytkownika
        /// Przypisuje do listy wszystkie aktywne kategorie z wykluczeniem podanej kategori id jesli jest rozne od 0
        /// </summary>
        /// <returns>Lista artukułów dla DropDownList</returns>
        public List<CategoriesDropDownListV> ReturnArticleCategoriesDDL()
        {
            try
            {               
                return _categoriesRepository.GetCategoriesByActiveFlag(_articleCategory.ArticleCategoryID);
            }
            catch (Exception ex)
            {
                InformationException = "Błąd podczas ładowania kategorii do listy rozwijalnej! " + ex.Message;
                return null;
            }
        }        

        /// <summary>
        /// Metoda użytkownika
        /// Sortuje wynik malejąco lub rosnąco wg kolumny grida
        /// </summary>
        /// <param name="source">Lista do posortowania, źródło</param>
        /// <param name="sortExpression">Określa kolumne po której będzie sortowanie</param>
        /// <param name="sortDirection">Określa kierunek sortowania</param>
        /// <returns> Lista posortowanych artykułów></returns>
        private void SortBy(IQueryable<ArtcileCategoriesGridV> pSource, string pSortExpression, string pSortDirection)
        {
            switch (pSortExpression)
            {
                case "Name":
                    if (pSortDirection == "Descending")
                    {
                        pSource.OrderByDescending(p => p.Name).ToList();
                    }
                    pSource = pSource.OrderBy(p => p.Name);
                    break;

                case "ParentName":
                    if (pSortDirection == "Descending")
                    {
                        pSource.OrderByDescending(p => p.ParentName).ToList();
                    }
                    pSource = pSource.OrderBy(p => p.ParentName);
                    break;


                case "SeqAllCategory":
                    if (pSortDirection == "Descending")
                    {
                        pSource.OrderByDescending(p => p.SeqAllCategory).ToList();
                    }
                    pSource = pSource.OrderBy(p => p.SeqAllCategory);
                    break;

                case "Status":
                    if (pSortDirection == "Descending")
                    {
                        pSource.OrderByDescending(p => p.Status).ToList();
                    }
                    pSource = pSource.OrderBy(p => p.Status);
                    break;

                case "ActiveFlag":
                    if (pSortDirection == "Descending")
                    {
                        pSource.OrderByDescending(p => p.ActiveFlag).ToList();
                    }
                    pSource = pSource.OrderBy(p => p.ActiveFlag);
                    break;

                case "ModifiedDate":
                    if (pSortDirection == "Descending")
                    {
                        pSource.OrderByDescending(p => p.ModifiedDate).ToList();
                    }
                    pSource = pSource.OrderBy(p => p.ModifiedDate);
                    break;                
            }            
        }

        /// <summary>
        /// Metoda użytkownika
        /// Zwraca wyszukane kategorie
        /// </summary>
        /// <param name="title">Tytuł</param>
        /// <param name="ididCategory">Kategoria nadrzędna</param>
        /// <param name="status">Status</param>
        /// <param name="active">Aktywny</param>
        /// <param name="sortExpression">Kolumna do pososrtowania</param>
        /// <param name="sortDirection">Kierunek sortowania</param>
        /// <returns>Lista posortowanych kategorii</returns>
        public void ListArticleCategoriesBySearch(string pTitle, int? pCategoryIDID, int? pStatus, bool? pActive, string pSortExpression, string pSortDirection)
        { 
            try
            {                
                _listGridArticleCategories = _categoriesRepository.GetCategoryBySearch(pTitle, pCategoryIDID, pStatus, pActive);
                SortBy(_listGridArticleCategories.AsQueryable(), pSortExpression, pSortDirection);
                foreach (ArtcileCategoriesGridV item in _listGridArticleCategories)
                {
                    if (item.DepthLevel == 1)
                    {
                        item.Name = "-  " + item.Name;
                    }
                }               
            }
            catch (Exception ex)
            {
                InformationException = "Błąd podczas ładowania kategorii! " + ex.Message;                
            }
        }

        /// <summary>
        /// Metoda użytkownika
        /// Zwraca maksymalną kolejność dla konkretnej rodziny
        /// </summary>
        /// <param name="idArticleCategory"></param>
        /// <returns>Maksymalna kolejność</returns>
        public int ReturnMaxSeqArticleCategoryById(int pArticleCategoryID)
        {
            List<ArticleCategoryT> listArticleCategories = new List<ArticleCategoryT>();
            
            try
            {                
                //listArticleCategories = _categoriesRepository.GetCategoryByIDIDCategoryIsNull(_categoriesRepository.GetCategoryByIdCategory(pArticleCategoryID).ArticleCategoryIDID);
                ReturnArticleCategoryById(pArticleCategoryID);
                listArticleCategories = _categoriesRepository.GetCategoryByIDIDCategoryIsNull(_articleCategory.ArticleCategoryIDID);
                return listArticleCategories.Max(x => x.SeqCategory);
            }
            catch (Exception ex)
            {
                InformationException = "Błąd podczas obliczania maksymalnej kolejności dla kategorii! " + ex.Message;
                return 0;
            }
        }

        /// <summary>
        /// Metoda użytkownika
        /// Zwraca słownik statusów
        /// </summary>
        /// <returns>Słownik statusów</returns>
        public IDictionary<int, string> ReturnStatusEnum()
        {
            try
            {
                return Enumeration.GetAll<StatusEnum>();
            }
            catch (Exception ex)
            {
                InformationException = "Błąd podczas ładowania statusu! " + ex.Message;
                return null;
            }
        }

        /// <summary>
        /// Metoda użytkownika
        /// Zwraca słownik Aktywności
        /// </summary>
        /// <returns>Słownik Aktywności</returns>
        public IDictionary<int, string> ReturnActiveEnum()
        {
            try
            {
                return Enumeration.GetAll<ActiveEnum>();
            }
            catch (Exception ex)
            {
                InformationException = "Błąd podczas ładowania aktywności! " + ex.Message;
                return null;
            }
        }

        /// <summary>
        /// Metoda użytkownika
        /// Zwraca słownik ilości wierszy w gridzie na jednej stronie
        /// </summary>
        /// <returns>Słownik ilości stron</returns>
        public IDictionary<int, string> ReturnPageSizeEnum()
        {
            try
            {
                return Enumeration.GetAll<PageSizeEnum>();
            }
            catch (Exception ex)
            {
                InformationException = "Błąd podczas ładowania numeru strony! " + ex.Message;
                return null;
            }
        }       

        
        /// <summary>
        /// Metoda użytkownika
        /// Zwiększa kolejność o jedną pozycję w górę w danej rodzinie
        /// </summary>
        /// <param name="ArticleCategory">Kategoria kliknięta</param>
        public void UpSeqArticleCategory(int pArticleCategoryID)
        {
            List<ArticleCategoryT> _listCategoriesTemp;
            List<ArticleCategoryT> _listCategoriesTemp2;
            ArticleCategoryT articleCategoryTemp2;
            try
            {                
                //kategoria zastepujaca(klikanej) _articleCategory
                ReturnArticleCategoryById(pArticleCategoryID);                
                //lista podkategorii zastepujacej(klikanej)
                _listCategoriesTemp = _categoriesRepository.GetCategoryByIDIDCategoryIsNull(_articleCategory.ArticleCategoryID);
                //kategoria zastepowana
                articleCategoryTemp2 = _categoriesRepository.GetCategoryBySeqAll(_articleCategory.SeqAllCategory - 1);
                if (articleCategoryTemp2.ArticleCategoryIDID != null && articleCategoryTemp2.ArticleCategoryIDID != _articleCategory.ArticleCategoryIDID)
                {
                    articleCategoryTemp2 = _categoriesRepository.GetCategoryByIdCategory((int)articleCategoryTemp2.ArticleCategoryIDID);
                }
                //lista podkategorii zastepewanej
                _listCategoriesTemp2 = _categoriesRepository.GetCategoryByIDIDCategoryIsNull(articleCategoryTemp2.ArticleCategoryID);
                //modyfikacja podkategorii zastepujacej kategorii                        
                foreach (ArticleCategoryT item in _listCategoriesTemp)
                {
                    item.SeqAllCategory = item.SeqAllCategory - _listCategoriesTemp2.Count - 1;
                    _categoriesRepository.UpdateCategory(item);
                }
                //modyfikacja zastepujacej kategorii(klikanej głównej)
                _articleCategory.SeqAllCategory = _articleCategory.SeqAllCategory - _listCategoriesTemp2.Count - 1;
                _articleCategory.SeqCategory = _articleCategory.SeqCategory - 1;
                _categoriesRepository.UpdateCategory(ArticleCategory);

                //modyfikacja podkategorii zastepowanej kategorii                        
                foreach (ArticleCategoryT item in _listCategoriesTemp2)
                {
                    item.SeqAllCategory = item.SeqAllCategory + _listCategoriesTemp.Count + 1;
                    _categoriesRepository.UpdateCategory(item);
                }
                //modyfikacja zastepowanej kategorii(głównej)    
                articleCategoryTemp2.SeqAllCategory = articleCategoryTemp2.SeqAllCategory + _listCategoriesTemp.Count + 1;
                articleCategoryTemp2.SeqCategory = articleCategoryTemp2.SeqCategory + 1;
                _categoriesRepository.UpdateCategory(articleCategoryTemp2);
            }
            catch (Exception ex)
            {
                InformationException = "Błąd podczas zmiany kolejności! " + ex.Message;
            }

        }

        /// <summary>
        /// Metoda użytkownika
        /// Zmniejsza kolejność o jedną pozycję w dół w danej rodzinie
        /// </summary>
        /// <param name="ArticleCategory">Kategoria kliknięta</param>
        public void DownSeqArticleCategory(int pArticleCategoryID)
        {
            List<ArticleCategoryT> _listCategoriesTemp;
            List<ArticleCategoryT> _listCategoriesTemp2;
            ArticleCategoryT articleCategoryTemp2;
            try
            {               
                //kategoria zastepujaca(klikanej) _artcileCategory
                ReturnArticleCategoryById(pArticleCategoryID);                
                //lista podkategorii zastepujacej(klikanej)
                _listCategoriesTemp = _categoriesRepository.GetCategoryByIDIDCategoryIsNull(_articleCategory.ArticleCategoryID);

                //kategoria zastepowana                
                articleCategoryTemp2 = _categoriesRepository.GetCategoryBySeqAll(_articleCategory.SeqAllCategory + _listCategoriesTemp.Count + 1);
                //lista podkategorii zastepewanej
                _listCategoriesTemp2 = _categoriesRepository.GetCategoryByIDIDCategoryIsNull(articleCategoryTemp2.ArticleCategoryID);


                //modyfikacja podkategorii zastepujacej kategorii                        
                foreach (ArticleCategoryT item in _listCategoriesTemp)
                {
                    item.SeqAllCategory = item.SeqAllCategory + _listCategoriesTemp2.Count + 1;
                    _categoriesRepository.UpdateCategory(item);
                }
                //modyfikacja zastepujacej kategorii(klikanej głównej)
                _articleCategory.SeqAllCategory = _articleCategory.SeqAllCategory + _listCategoriesTemp2.Count + 1;
                _articleCategory.SeqCategory = _articleCategory.SeqCategory + 1;
                _categoriesRepository.UpdateCategory(_articleCategory);

                //modyfikacja podkategorii zastepowanej kategorii                        
                foreach (ArticleCategoryT item in _listCategoriesTemp2)
                {
                    item.SeqAllCategory = item.SeqAllCategory - _listCategoriesTemp.Count - 1;
                    _categoriesRepository.UpdateCategory(item);
                }
                //modyfikacja zastepowanej kategorii(głównej)    
                articleCategoryTemp2.SeqAllCategory = articleCategoryTemp2.SeqAllCategory - _listCategoriesTemp.Count - 1;
                articleCategoryTemp2.SeqCategory = articleCategoryTemp2.SeqCategory - 1;
                _categoriesRepository.UpdateCategory(articleCategoryTemp2);
            }
            catch (Exception ex)
            {
                InformationException = "Błąd podczas zmiany kolejności! " + ex.Message;
            }
        }
        
        /// <summary>
        /// Metoda użytkownika
        /// Usuwa wybraną kategorię
        /// </summary>
        /// <param name="ArticleCategory">Zaznaczona kategoria</param>
        public void DeleteArticleCategory(int pArticleCategoryID)
        {
            ArticlesRepository articlesRepository = new ArticlesRepository(_context);
            List<ArticleCategoryT> listArticleCategoriesTemp;
            List<ArtilcesGridV> listArticlesTemp;
            ArticleCategoryT articleCategoryTemp;
            InformationUserDictionary informationUserDictionary = InformationUserDictionary.Instance;
            try
            {
                ReturnArticleCategoryById(pArticleCategoryID);                
                //czy sa jakies artykuly podpiete do kategorii
                listArticlesTemp = articlesRepository.GetArticleBySearch("", _articleCategory.ArticleCategoryID, null, null);
                if (listArticlesTemp.Count == 0)
                {
                    //czy ma podkategorie, zabronione usuwanie kategorii z podkategoriami
                    listArticleCategoriesTemp = _categoriesRepository.GetCategoryByIDIDCategoryIsNull(_articleCategory.ArticleCategoryID);
                    if (listArticleCategoriesTemp.Count == 0)
                    {
                        //zapisanie idid
                        int? articleCategoryIDID = _articleCategory.ArticleCategoryIDID;
                        //usuwanie kategorii                        
                        _categoriesRepository.DeleteCategory(_articleCategory);
                        //przypisanie ponownie idid bo sie kasuje po delete, nie wiem dlaczego
                        _articleCategory.ArticleCategoryIDID = articleCategoryIDID;

                        //modyfikacja seqAll dla wszystkich
                        listArticleCategoriesTemp = _categoriesRepository.GetAll();
                        for (int i = _articleCategory.SeqAllCategory + 1; i <= listArticleCategoriesTemp.Count() + 1; i++)
                        {
                            articleCategoryTemp = _categoriesRepository.GetCategoryBySeqAll(i);
                            articleCategoryTemp.SeqAllCategory = i - 1;
                            _categoriesRepository.UpdateCategory(articleCategoryTemp);
                        }

                        //modyfikacja seq dla jednej rodziny
                        listArticleCategoriesTemp = _categoriesRepository.GetCategoryByIDIDCategoryIsNull(_articleCategory.ArticleCategoryIDID);
                        if (listArticleCategoriesTemp.Count + 1 != _articleCategory.SeqCategory)
                        {
                            for (int i = _articleCategory.SeqCategory; i <= listArticleCategoriesTemp.Count(); i++)
                            {
                                articleCategoryTemp = _categoriesRepository.GetCategoryBySeqAndIDIDCategoryID(i + 1, _articleCategory.ArticleCategoryIDID);
                                articleCategoryTemp.SeqCategory = i;
                                _categoriesRepository.UpdateCategory(articleCategoryTemp);
                            }
                        }

                        //nie zawiera podrzednych kategorii

                        InformationSuccess = informationUserDictionary.GetInformationUserText(1);                   
                   
                    }
                    else
                    {
                        //zawiera podrzedne kategorie- komunikat                   
                        InformationNotice = informationUserDictionary.GetInformationUserText(2);                    
                    }
                }
                else
                {
                    //zawiera artykuly w wybranej aktegorii- komunikat                
                    InformationNotice = informationUserDictionary.GetInformationUserText(3);                
                }
            }
            catch (Exception ex)
            {
                InformationException = "Błąd podczas usuwania zaznaczonych kategorii! " + ex.Message;                
            }
            
        }

        /// <summary>
        /// Metoda użytkownika
        /// Modyfikuje wybraną kategorię
        /// </summary>
        /// <param name="ArticleCategory">Wybrana kategoria</param>
        public void UpdateArticleCategory(ArticleCategoryT pArticleCategory)
        {
            try
            {
                InformationUserDictionary _informationUserDictionary = InformationUserDictionary.Instance;



                ReturnArticleCategoryById(pArticleCategory.ArticleCategoryID);
                //_articleCategory2 = _categoriesRepository.GetCategoryByIdCategory(ArticleCategory.ArticleCategoryID);

                //jezeli nalezy do tej samej kategorii nadrzednej
                if (ArticleCategory.ArticleCategoryIDID == _articleCategory.ArticleCategoryIDID)
                {
                    //uzupelniam dane, nastepnie wykonuje update
                    pArticleCategory.SeqAllCategory = _articleCategory.SeqAllCategory;
                    pArticleCategory.SeqCategory = _articleCategory.SeqCategory;
                    pArticleCategory.DepthLevel = _articleCategory.DepthLevel;
                    _categoriesRepository.UpdateCategory(pArticleCategory);
                }
                else
                {
                    DeleteArticleCategory(pArticleCategory.ArticleCategoryID);
                    InsertArticleCategory(pArticleCategory);
                }

                InformationSuccess = _informationUserDictionary.GetInformationUserText(4);
            }
            catch (Exception ex)
            {
                //System.Diagnostics.Debug.WriteLine(ex.Message);
                InformationException = "Błąd podczas zmiany kategorii! " + ex.Message;
            }
        }

        
        /// <summary>
        /// Dodaje nową kategorię
        /// </summary>
        /// <param name="ArticleCategory">Nowa kategoria</param>
        /// <returns></returns>
        public int InsertArticleCategory(ArticleCategoryT pArticleCategory)
        {
            int seq;
            int seqAll;
            int countAll;
            ArticleCategoryT articleCategory2;
            List<ArticleCategoryT> _listCategoriesCount;
            try
            {
                
                InformationUserDictionary _informationUserDictionary = InformationUserDictionary.Instance;



                //zliczanie wszystkich kategorii
                _listCategoriesCount = _categoriesRepository.GetAll();
                if (_listCategoriesCount.Count != 0)
                {
                    countAll = _listCategoriesCount.Max(x => x.SeqAllCategory);
                    seqAll = countAll;
                }
                else
                {
                    countAll = 0;
                    seqAll = 0;
                }

                //koniec zliczania

                if (ArticleCategory.ArticleCategoryIDID != null)
                {
                    
                    _articleCategory = _categoriesRepository.GetCategoryByIdIdCategory(pArticleCategory.ArticleCategoryIDID);
                    ArticleCategory.DepthLevel = _articleCategory.DepthLevel;
                    ArticleCategory.DepthLevel += 1;

                    _listCategoriesCount = _categoriesRepository.GetCategoryByIDIDCategoryIsNull(pArticleCategory.ArticleCategoryIDID);
                    if (_listCategoriesCount.Count != 0)
                    {
                        seqAll = _listCategoriesCount.Max(x => x.SeqAllCategory);
                        seq = _listCategoriesCount.Max(x => x.SeqCategory);
                    }
                    else
                    {
                        articleCategory2 = _categoriesRepository.GetCategoryByIdCategory((int)pArticleCategory.ArticleCategoryIDID);
                        seqAll = articleCategory2.SeqAllCategory;
                        seq = 0;
                    }
                }
                else
                {
                    pArticleCategory.DepthLevel = 0;
                    _listCategoriesCount = _categoriesRepository.GetCategoryByIDIDCategoryIsNull(null);
                    if (_listCategoriesCount.Count != 0)
                    {
                        seq = _listCategoriesCount.Max(x => x.SeqCategory);
                    }
                    else
                    {
                        seq = 0;
                    }
                }

                countAll += 1;
                seqAll += 1;
                seq += 1;

                while (seqAll < countAll)
                {
                    countAll -= 1;

                    articleCategory2 = _categoriesRepository.GetCategoryBySeqAll(countAll);
                    articleCategory2.SeqAllCategory = countAll + 1;
                    _categoriesRepository.UpdateCategory(articleCategory2);
                }


                pArticleCategory.SeqAllCategory = seqAll;
                pArticleCategory.SeqCategory = seq;                

                //ArticleCategory.ArticleCategoryIDID = 1213123;
                int idArticleCategory = _categoriesRepository.InsertCategory(pArticleCategory);
                
                InformationSuccess = _informationUserDictionary.GetInformationUserText(5);
                return idArticleCategory;               
                
            }
            catch (Exception ex)
            {
                InformationException = "Błąd podczas dodawania kategorii! " + ex.Message;
                return 0;
            }
        }

        
    }
    
}
